using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace dataplotcli {
    class GridLogic {

        
       
        // Things that can be done to the grid.

        // Cell Item Selected
        // returns the message to 
        // write to the status bar
        public string select_cell(int x, int y) {

            this.current_selected_cell = this.get_cell_preview(x,y);

            if(/*this.copy_current_image_to_cell*/ false) {
                //this.insert_photo_into_grid(x, y, this.current_selected_photo, panel_to_draw_to);
                //this.copy_current_image_to_cell = false;
                // TODO: do something as far as drawing the photo in the cell.
                return "Wrote image " + this.current_selected_photo.Name + " to cell " +  "["
                    + (x - (x % cell_height)) / cell_height
                    + ", "
                    + (y - (y % cell_width)) / cell_width
                    + "] ";
            } else {
                selected_draw_panel_state = new Bitmap(this.draw_panel_state);

                Graphics.FromImage(selected_draw_panel_state).DrawRectangle(
                    new Pen(Brushes.LightBlue, 4f),
                    new Rectangle((x - (x % cell_height)), 
                    (y - (y % cell_width)), cell_height, cell_height));

                return                    
                    "Cell ["
                    + (x - (x % cell_height)) / cell_height
                    + ", "
                    + (y - (y % cell_width)) / cell_width
                    + "] " + "selected.";
            }

        }

        // get preview content of current selected cell

        public List<PlotableType> preview_selected_cell() {
            return this.current_selected_cell;
        }

        // Photo selected 
        public void select_photo(PlotablePhoto photo_selected) {
            this.current_selected_photo = photo_selected;
        }

        // Preview items in cell

        public List<PlotableType> get_cell_preview(int x, int y) {
            this.last_hover_x = x;
            this.last_hover_y = y;
            return this.get_cell_content(x, y);
        }

        // get cell photo count
        public int get_cell_photo_count(int x, int y) {
            return this.get_cell_content(x, y).Count;
        }

        // get cell content, w/o setting last hover
        public List<PlotableType> get_cell_content(int x, int y) {
            return this.data_grid.getFromCell(this.get_cell_index_location(x, y));
        }

        // Insert item into cell.

        public Bitmap insert_photo_into_grid(int x, int y, PlotablePhoto toPlot) {

            if (null != toPlot) {
                List<PlotableType> coordinate_plot_list = data_grid.getFromCell(
                    (x - (x % cell_height)) / cell_height,
                    (y - (y % cell_width)) / cell_width);
                coordinate_plot_list.Add(toPlot);

                return this.selected_draw_panel_state;
            } else {
                return null;
            }
        }

        public void draw_cell(int x, int y) {
            if (this.get_cell_content(x, y).Count > 0) {
                Graphics.FromImage(draw_panel_state).
                    DrawImage(new Bitmap(((PlotablePhoto)(this.get_cell_content(x, y)[0])).PlotedImage, cell_width, cell_height),
                    (x - (x % cell_height)),
                    (y - (y % cell_width)));
               this.select_cell(x, y);
            }
        }

        // Blank out the grid, in white

        public void blank_grid(Brush bg_grid_color) {
            draw_panel_state = new Bitmap(grid_width, grid_height);
            Graphics.FromImage(draw_panel_state).
                FillRectangle(bg_grid_color, new Rectangle(0, 0, grid_width, grid_height));
        }

        // draw the grid lines

        public void draw_grid_lines(Brush line_brush_color) {
            for (int horizontal_line_x = cell_height; 
                horizontal_line_x < grid_height; 
                horizontal_line_x += cell_height) {

                Graphics.FromImage(draw_panel_state).DrawLine(
                    new Pen(line_brush_color),
                    new Point(0, horizontal_line_x),
                    new Point(grid_width - 1, horizontal_line_x));
            }

            for (int vertical_line_x = cell_width; 
                vertical_line_x < grid_width; 
                vertical_line_x += cell_width) {

                Graphics.FromImage(draw_panel_state).DrawLine(
                    new Pen(line_brush_color),
                    new Point(vertical_line_x, 0),
                    new Point(vertical_line_x, grid_height - 1));
            }
        }

        /// <summary>
        /// 
        /// Is hovering going on?
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>

        public bool hovering(int x, int y) {
            return
            !(((x / this.cell_height) == (this.last_hover_x / this.cell_height)) &&
             ((y / this.cell_width) == (this.last_hover_y / this.cell_width)));
        }


        // remove an item from a cell

        // rescale grid ?? TODO


        // Get cell location by pixel
        public Point get_cell_pixel_location(int x, int y) {
            return new Point(
                 (x - (x % cell_height)),
                 (y - (y % cell_width)));
        }

        // Get cell location by index
        public Point get_cell_index_location(int x, int y) {
            return new Point(
                (x - (x % cell_height)) / cell_height,
                (y - (y % cell_width)) / cell_width);
        }

        // current_selected_cell_list_index_location
        public void reset_current_selected_cell_list_index_location() {
            this.current_selected_cell_list_index_location = 0;
        }

        public void current_cell_list_go_forward() {
            Go_To_NextOrPreviousEntry_InCurrentSelectedCell = next_or_prev_t.NEXT;
        }

        public void current_cell_list_go_backward() {
            Go_To_NextOrPreviousEntry_InCurrentSelectedCell = next_or_prev_t.PREV;
        }

        // Grid State Fields

        private Matrix<List<PlotableType>> data_grid; // Data Backend of grid. 

        private int cell_width; // width of cells, used to scale pixels
        private int cell_height; // height of cells, used for scaling

        private int grid_width; // width of cells, used to scale pixels
        private int grid_height; // height of cells, used for scaling

        private int last_hover_x; // last row value that was hovered over
        private int last_hover_y; // last column value that was hovered over. 

       



        // This booleans says wheather the next 
        // cell that is clicked should have the 
        // current photo selected copied to it
        //public bool copy_current_image_to_cell = false;

        /// <summary>
        /// The current cell that is selected. 
        /// </summary>
        private List<PlotableType> current_selected_cell;


        /// <summary>
        /// This is the index that we are in the current list
        /// taken from the current cell.
        /// </summary>
        private int current_selected_cell_list_index_location;

        /// <summary>
        /// This is a switch to controll if you go forward
        /// or back in current list/cell.
        /// </summary>
        private enum next_or_prev_t { NEXT, PREV };
        private next_or_prev_t Go_To_NextOrPreviousEntry_InCurrentSelectedCell=next_or_prev_t.NEXT;


        /// <summary>
        /// The current photo to be displayed in the 
        /// large picturebox
        /// </summary>
        private PlotablePhoto current_selected_photo;

        /// <summary>
        /// the viewable state of the grid
        /// </summary>
        private Bitmap draw_panel_state;


        /// <summary>
        /// 
        /// the viewable state of the grid, with 
        /// the current cell selected. 
        /// </summary>
        private Bitmap selected_draw_panel_state;


        // Properties:

        /// <summary>
        /// Read only property that gets the 
        /// current photo that is selected.
        /// 
        /// </summary>
        public PlotablePhoto CurrentSelectedPhoto {
            get {
                return this.current_selected_photo;
            }
        }

        /// <summary>
        /// Read only property that gets the current
        /// selected cell in the grid.
        /// </summary>
        public List<PlotableType> CurrentSelectedCell {
            get {
                return this.current_selected_cell;
            }
        }

        /// <summary>
        /// This is a clever little property to get the next 
        /// plotable item from the cell. Useful for getting 
        /// partial ammount of entries from the cell.
        /// </summary>
        public PlotableType NextOrPreviousEntryInCurrentSelectedCell {
            get {
                if (current_selected_cell.Count > 0) {
                    if (Go_To_NextOrPreviousEntry_InCurrentSelectedCell == next_or_prev_t.NEXT) {
                        current_selected_cell_list_index_location++;
                        if (current_selected_cell_list_index_location >= current_selected_cell.Count) {
                            current_selected_cell_list_index_location = 0;
                        }
                    } else if (Go_To_NextOrPreviousEntry_InCurrentSelectedCell == next_or_prev_t.PREV) {
                        current_selected_cell_list_index_location--;
                        if (current_selected_cell_list_index_location < 0) {
                            current_selected_cell_list_index_location = current_selected_cell.Count - 1;
                        }
                    } else {
                        current_selected_cell_list_index_location++;
                    }

                    if (!(current_selected_cell_list_index_location >= 0 &&
                        current_selected_cell_list_index_location < current_selected_cell.Count)) {
                        current_selected_cell_list_index_location = 0;
                    } 

                    return current_selected_cell[current_selected_cell_list_index_location];
                } else {
                    return null;
                }
            }
        }

        public int number_of_entries_to_load_at_a_time {
            get {
                int default_value = 6;
                if (current_selected_cell.Count < default_value) {
                    return current_selected_cell.Count;
                } else {
                    return default_value;
                }
            }
        }

        /// <summary>
        /// This is a readonly property to get the
        /// bitmap of the panel w/ the selected square
        /// highlighted
        /// </summary>
        public Bitmap SelectedDrawPanelState {
            get {
                return this.selected_draw_panel_state;
            }
        }

        /// <summary>
        /// This is a readonly property to get the 
        /// bitmap of the panel. I don't even think 
        /// it should be available, but we'll see. 
        /// </summary>
        public Bitmap DrawPanelState {
            get {
                return this.draw_panel_state;
            }
        }


        // contructor:

        public GridLogic(int cell_width, int cell_height, int grid_width, int grid_height) {

            this.cell_height = cell_height;
            this.cell_width = cell_width;
            this.grid_height = grid_height;
            this.grid_width = grid_width;

            data_grid = MatrixFactory.grid_factory(
                this.grid_height / this.cell_height,
                this.grid_width / this.cell_width);

            for (int row_i = 0; row_i < this.grid_height / this.cell_height; row_i++) {
                for (int col_i = 0; col_i < this.grid_width / this.cell_width; col_i++) {
                    data_grid.setCellTo(row_i, col_i, new List<PlotableType>());
                }
            }

        }


    }
}
